# game functions
from pdb import set_trace as D

DRIVER = 'ON'
import random
import sys

def init_game(data):

    data['skill_deck']              = init_skill_deck(data['skills'])
    data['event_deck']              = init_event_deck(data['events'])
    data['players']                 = init_players(data['characters'])
    data['game']['current_player']  = init_first_player(data['players'])
    data['game']['admiral']         = init_admiral(data['players'],data['characters'])
    data['game']['president']       = init_president(data['players'],data['characters'])
    data['quorum_deck']             = init_quorum_deck(data['quorum'])
    data['board']['ship_locations'] = init_ships(data['board']['ship_locations'],data['players'])
    
    (data['players'],data['loyalty_deck']) = init_loyalty_deck(data['loyalty'],data['players'],'initial')
    (data['players'],data['skill_deck']) = init_skill_cards(data['players'],data['skill_deck'],data['characters'],'initial')

    return data

def init_first_player(players):
    current = random.randint(0,len(players)-1)

    return current

def init_event_deck(card_data):
    deck = dict(deck=[],play=[],discard=[])

    deck['deck'] = card_data.keys()
    random.shuffle(deck['deck'])
    return(deck)

def init_skill_deck(card_data):
    decks=dict()
    for i in card_data:
        decks[i]=dict(deck=[],play=[],discard=[])
        for j in card_data[i]:
            for k in range(0,card_data[i][j]['number']):
                decks[i]['deck'].append(j)
                
        random.shuffle(decks[i]['deck'])

    return(decks)

def init_loyalty_deck(data,players,phase):
    if phase=='initial':
        cylon_deck = ['cylon_one','cylon_two','cylon_three','cylon_four']
        random.shuffle(cylon_deck)
        loyalty = []
        if len(players)==3:
            cylon=1
            notacylon=5
        elif len(players)==4:
            cylon=1
            notacylon=6
        elif len(players)==5:
            cylon=2
            notacylon=8
        elif len(players)==6:
            cylon=2
            notacylon=9            

        for i in players:
            if i['character']=='boomer' or i['character']=='baltar':
                notacylon += 1

        for i in range(0,cylon):
            loyalty.append(cylon_deck.pop())

        for i in range(0,notacylon):
            loyalty.append('notacylon')

        random.shuffle(loyalty)
        for i in players:
            i['loyalty'].append(loyalty.pop())
            if i['loyalty'][len(i['loyalty'])-1]!='notacylon':
                i['state']='cylon'

        if len(players)==4 or len(players)==6:
            loyalty.append('sympathizer')
            random.shuffle(loyalty)

        loyalty = dict(loyalty=loyalty,cylon_deck=cylon_deck)

    elif phase=='sleeper':
        print 'sleeper agent phase - under construction'

    return players, loyalty

def init_quorum_deck(data):
    deck = dict(deck=[],play=[],hand=[],discard=[])

    for i in data:
        for j in range(0,data[i]['number']):
            deck['deck'].append(i)
                
    random.shuffle(deck['deck'])
    deck['hand'].append(deck['deck'].pop())
    return(deck)    

def init_players(characters):
    # This function asks for players to play the game,
    # and stores their names.
    tries = 3
    while tries:
        if DRIVER == 'ON':
            num_players = 3
        else:
            num_players = int('0'+raw_input('Enter Number of Players:'))
        if (3 <= num_players <= 6):
            break

        tries -= 1
        if tries == 0:
            sys.exit('I give up on you, you frakking toaster, go back to the scrap heap.')

        print ('THREE through SIX, you frakking Cylon...')

    players=[]
    for i in range(0,num_players):
        if DRIVER == 'ON':
            player_name = 'Ben' + str(i)
        else:
            player_name = raw_input('\n\nPlayer %d, enter your name:' %(i+1))
            
        players = init_characters(player_name,players,characters)

    return players

def init_characters(player_name,players,characters):
    # This function prompts the input 'player' to select a character,
    # and manages the remaining characters available to choose per the rules

    num_players_added = len(players)
    while (len(players)==num_players_added):
        # Get the available characters, prompt the player to choose, and display the choice
        avail_chars = init_avail_chars(players,characters)
        print '\n\n',player_name, ', the available characters are:'
        for i,j in enumerate(avail_chars):
            print int(i+1), '. ', characters[j]['display']['name']

        tries = 3
        while tries:
            if DRIVER=='ON':
                choice = 1
            else:
                choice = int('0'+raw_input('Please enter the number of the Character you wish to consider:'))
##            print 'choice: ', choice
##            print 'length: ', int(len(avail_chars))
            if (1 <= choice <= int(len(avail_chars))):
                break

            tries -= 1
            if tries == 0:
                print('Couldn\'t make up your mind?  Cylon?  How about I just pick on for you...')
                choice = 1

            print ('Try again, toaster...')
        display('character',avail_chars[int(choice-1)],characters)


        # Ask for confirmation, or else return to choice
        if DRIVER=='ON':
            confirm = 'y'
        else:
            confirm = raw_input('Press "y" to confirm choice: ')
        if confirm=='y':
            chosen_character = avail_chars[int(choice-1)]
            chosen_location = characters[chosen_character]['data']['setup']
            if chosen_location == 'viper':
                if DRIVER=='ON':
                    chosen_location='swest'
                else:
                    loc = raw_input('Select (S) for South West Viper location, or (U) for South East Viper location:')
                    if loc=='S':
                        chosen_location='swest'
                    else:
                        chosen_location='seast'
                                        
            players.append(
                dict(
                    name=player_name,
                    character=chosen_character,
                    location=chosen_location,
                    state='human',
                    loyalty=[],
                    skills=[]
                    )
                )
        
    return players

def init_avail_chars(players,characters):
    # This function compiles the list of available characters according to the game rules

    # Init a list of all characters and their roles
    avail_chars=[]
    char_roles=[]
    for i in characters:
        avail_chars.append(i)
        char_roles.append(characters[i]['data']['role'])

    # If no choices made, make all chars available.
    if not players:
        return avail_chars

    else:

        # init some counters for each character type
        char_count = dict(
            pol=dict(value=0,role='politician'),
            mil=dict(value=0,role='military'),
            pil=dict(value=0,role='pilot'),
            )        

        # Remove characters that have all ready been chosen
        for i in players:

            if characters[i['character']]['data']['role']=='politician':
                char_count['pol']['value'] += 1
            elif characters[i['character']]['data']['role']=='military':
                char_count['mil']['value'] += 1
            elif characters[i['character']]['data']['role']=='pilot':
                char_count['pil']['value'] += 1            

            for j in range(0,len(avail_chars)):
                if i['character'] == avail_chars[j]:
                    del avail_chars[j]
                    del char_roles[j]
                    break

        # loop through the types, and again,
        # and if any type is greater than any other type,
        # remove from list of avail roles
        avail_roles = ['politician','military','pilot']
        unavail_roles = []
        for i in char_count:
            for j in char_count:
                if char_count[i]['value'] > char_count[j]['value']:
                    unavail_roles.append(char_count[i]['role'])
                    break

        if not unavail_roles:
            None
        else:
            for i in unavail_roles:
                avail_roles.remove(i)
                
            unavail_chars = []
            for i in range(0,len(avail_chars)):
                for j in unavail_roles:
                    if char_roles[i]==j:
                        unavail_chars.append(avail_chars[i])
                        
            if not unavail_chars:
                None
            else:
                for i in unavail_chars:
                    avail_chars.remove(i)
    
    return avail_chars
        
def init_skill_cards(players,skills,characters,phase):
    # This function gets the skill cards for a player,
    # and gives them the option of which category if there is a choice.
    # It also checks the player location (if 'sick', then only 1 card is drawn)
    for i in players:
        avail_categories=['V','Y']
        cards_chosen = 0
        while cards_chosen < 3:
            print i['name'], '\\', i['character'], 'Select Skill card from the following categories:'
            for j in characters[i['character']]['data']['cards']:
                for k in j['categories']:
                    if k=='politics':
                        print '(P)olitics; ',
                        avail_categories.append('P')
                    elif k=='piloting':
                        print 'Pilotin(G); ',
                        avail_categories.append('G')                        
                    elif k=='leadership':
                        print '(L)eadership; ',
                        avail_categories.append('L')                        
                    elif k=='tactics':
                        print '(T)actics; ',
                        avail_categories.append('T')                        
                    elif k=='engineering':
                        print '(E)ngineering; ',
                        avail_categories.append('E')                        

            if DRIVER=='ON':
                avail_categories.append('P')#,'G','L','T','E')
                choice = 'P'
            else:
                choice = raw_input('\nPress Letter to confirm choice, or (V) to view character, or (Y) to view loyalty: ')

            if avail_categories.__contains__(choice):
                if choice=='P':
                    i['skills'].append(skills['politics']['deck'].pop())
                    cards_chosen += 1
                elif choice=='G':
                    i['skills'].append(skills['piloting']['deck'].pop())
                    cards_chosen += 1
                elif choice=='L':
                    i['skills'].append(skills['leadership']['deck'].pop())
                    cards_chosen += 1
                elif choice=='T':
                    i['skills'].append(skills['tactics']['deck'].pop())
                    cards_chosen += 1
                elif choice=='E':
                    i['skills'].append(skills['engineering']['deck'].pop())
                    cards_chosen += 1
                elif choice=='V':
                    display('character',i['character'],characters)
                elif choice=='Y':
                    print i['loyalty']
                       

    return players,skills

def init_admiral(players,characters):
    # This function chooses the player/character that is next in line to be admiral.
    # Admiral cannot be revealed Cylon/Sympathizer.
    # Admiral cannot be in the 'brig'.

    for i in players:
        print i

    for i in players:
        if (i['location']!='brig' and
            (i['state']!='revealed_cylon' or i['state']!='sympathizer')):
            if i['character']=='adama':
                admiral = 'adama'
                break
            elif i['character']=='saul':
                admiral = 'saul'
                break                
            elif i['character']=='helo':                
                admiral = 'helo'
                break
            elif i['character']=='lee':                
                admiral = 'lee'
                break
            elif i['character']=='starbuck':                
                admiral = 'starbuck'
                break
            elif i['character']=='boomer':                
                admiral = 'boomer'
                break
            elif i['character']=='chief':                
                admiral = 'chief'
                break
            elif i['character']=='zarek':                
                admiral = 'zarek'
                break
            elif i['character']=='baltar':                
                admiral = 'baltar'
                break
            elif i['character']=='roslin':                
                admiral = 'roslin'
                break

    return admiral

def init_president(players,characters):
    # This function chooses the player/character that is next in line to be president.
    # President cannot be revealed Cylon/Sympathizer.

    for i in players:
        if (i['state']!='revealed_cylon' or i['state']!='sympathizer'):
            if i['character']=='roslin':
                president = 'roslin'
                break
            elif i['character']=='baltar':
                president = 'baltar'
                break                
            elif i['character']=='zarek':                
                president = 'zarek'
                break
            elif i['character']=='lee':                
                president = 'lee'
                break
            elif i['character']=='adama':                
                president = 'adama'
                break
            elif i['character']=='helo':                
                president = 'helo'
                break
            elif i['character']=='chief':                
                president = 'chief'
                break
            elif i['character']=='boomer':                
                president = 'boomer'
                break
            elif i['character']=='saul':                
                president = 'saul'
                break
            elif i['character']=='starbuck':                
                president = 'starbuck'
                break

    return president

def init_ships(locations,players):

    locations = ships(1,'basestar','cylon_fleet','west',locations)
    locations = ships(1,'raider','cylon_fleet','west',locations)
    locations = ships(1,'raider','cylon_fleet','west',locations)
    locations = ships(1,'raider','cylon_fleet','west',locations)
    locations = ships(1,'viper','hangar','swest',locations)
    locations = ships(1,'viper','hangar','seast',locations)
    locations = ships(1,'civilian','civilian_fleet','east',locations)
    locations = ships(1,'civilian','civilian_fleet','east',locations)    

    for i in players:
        if i['location']=='swest':
            locations = ships(1,'viper','hangar','swest',locations)
        elif i['location']=='seast':
            locations = ships(1,'viper','hangar','seast',locations)            

    return locations

    
def display(category, ID, data):
    if category=='character':
        characters=data
        print '\n\n'
        print characters[ID]['display']['name']
        print characters[ID]['display']['role']
        print '________________________________________'
        print 'ABILITY - ', characters[ID]['display']['ability_name']
        print characters[ID]['display']['ability_text']
        print '________________________________________'
        print 'SKILL - ', characters[ID]['display']['skill_name']
        print characters[ID]['display']['skill_text']
        print '________________________________________'
        print 'QUIRK - ', characters[ID]['display']['quirk_name']
        print characters[ID]['display']['quirk_text']
        print '________________________________________'
        for i in range(0,len(characters[ID]['display']['cards'])):
            for j in range(0,len(characters[ID]['display']['cards'][i]['categories'])):
                if j>0:
                    print '/',
                print characters[ID]['display']['cards'][i]['categories'][j],
            print characters[ID]['display']['cards'][i]['value']
        print '________________________________________'
        print 'START: ', characters[ID]['display']['setup']
        print '\n'
            
    elif category=='board':
        board = data['board']
        players = data['players']

        for i in board['resource']:
            print board['resource'][i]['name'],':  ', board['resource'][i]['current'], ' (Low: ', board['resource'][i]['low'], ')'

        print board['jump_track']['name'],':  ',board['jump_track']['current'], ' (-3 @ ',board['jump_track']['emergency_minus3'],', -1 @ ',board['jump_track']['emergency_minus1'],')'

        print board['boarding_track']['name'],':  ',board['boarding_track']['slot_1'],'>>>',board['boarding_track']['slot_2'],'>>>',board['boarding_track']['slot_3'],'>>>',board['boarding_track']['slot_4']

        print 'SHIP LOCATIONS:'
        for i in board['ship_locations']:
            print i,':  ',
            for j in board['ship_locations'][i]:
                print j['ship'],'-',
                for k in j['damage']:
                    print k,'; ',
            print '\n',

        print 'GALACTICA LOCATIONS:'
        for i in board['galactica_locations']:

            empty = True
            for j in players:
                if j['location']==i:
                    if empty==True:
                        empty = False
                        print i,':  ',
                    print j['character'],'; ',

            if empty==False:
                print '\n',            
                    
    else:
        print 'No category to display'

# event card functions

# Choice Function:  Gives the input player a choice, which is results in one of several lists of results.  The result list itself may be a list of further event functions.

def choice(player,results):

    # Prompt input player to choose between the number of result choices:
    # Send back to main loop to resolve result?
    None

# resource function: alter the input board element type by the input value
def resource(category,value):

    board['resource'][category]['current'] += value

    # If input resource exceeds maximum, set as maximum
    if board['resource'][category]['current'] > board['resource'][category]['high']:
        board['resource'][category]['current'] = board['resource'][category]['high']
        return

    # If input resource below zero, set as zero
    elif board['resource'][category]['current'] < 0:
        board['resource'][category]['current'] = 0        
##        endOfGameCheck()
        return

# skills function:  alter the input 'player's (or 'all' for all players)
# skill cards by the input 'value' (or 'all' for all cards),
# for the input 'category' (or 'any for player choice, or 'random' for random choice)
def skills(player,category,value):
    None

# loyalty function:  allows the input 'viewer'
# to view the input random 'value' of loyalty cards from the input 'player'



# title function:  assign input 'title' to input 'player' (or gives input player choice of who to give title to, if input has _choice appended to it)

# basestars function:  cause basestars to take input action
##                function='basestars',
##                arguments=dict(action='raiders')
##                arguments=dict(action='nukes')
##                arguments=dict(action='heavies')

# raiders function:  cause raiders to activate


# heavies function:  cause heavy raiders to activate


# jump function:  cause jump prep to move (and resolve) by input 'value'
#                jump(value=+1) or jump(value='now') for emergency jump if prep is on last one or two levels.
# (calling function must prevent jump function if prep not far enough along)
# If emergency jump, roll for population loss according to current jump prep status.
# Also, if 'pursuit' is 'enabled',
#  then shuffle event 'thirty-three' into the 'event_deck' from the 'in_play_deck'
# Also, set 'pilot_training' to 'good'
# Also, set 'massive_deployment' to 'inactive'


# ships function:
# Cause number of input 'value'
#   of input 'category' of ship at input "from" location, 'loc_from',
#   to be moved to input "to" location, 'loc_to'.
# Also, if 'basestar' or 'civilian' moves to 'destroyed',
#   and 'pursuit' is 'enabled', then <pursuit(status='disable')>
# Check that ships exist to be moved(?)    

def ships(value,category,loc_from,loc_to,locations):
    for i in range(0,value):
        random.shuffle(locations[loc_from])
        for j in locations[loc_from]:
            if j['ship']==category:
                locations[loc_to].append(j)
                locations[loc_from].remove(j)
                break
    
    return locations

# nukes function:  perform input action on nuke stores by input value


# Challenge function:  prompt players in turn to select cards for the challenge.


# Boarding function:  add input 'value' boarders to start of boarding track,
# and move existing boarders up 1 if input 'activate'=True.


# Sabotage function:  indicates cylon detector is 'damaged',
# which prevents any player from looking at another player's loyalty cards.
# Or indicates it is working, or 'good'.  Stored in game data under cylon_detector.
# arguments:  status='damaged'
# arguments:  status='good'


# Roll function:  if 1d8 roll is equal to or lower than the input "threshold", then do input effect.


# Crisis function:  draws and resolves a crisis card.


# Pursuit function:  input 'status' enables or disables "relentless pursuit",
# which adds the 'thirty-three' event card back into the event deck after it is resolved.

# Shuffle function:  shuffles input 'event' card into the deck.


# Jamming function:  input 'status' indicates 'jammed',
# in which case the 'communications' game value (and location) is in-operative,
# Or indicates 'good', in which case the communications location is operative.


# Communications Space function:  perform the Comms action from the comms space on the board.
# Also, check if 'communications' are 'jammed' or 'good' as a prerequisite for using the action.


# Training function:  if input 'status' is 'training', then update 'pilot_training' to 'training',
# and then all unmanned vipers have -2 attack rolls.
# if 'status' is 'good', update to 'good', then no penalty.


# Viper Attack function:  perform the Viper attack action on the input 'target category',
# and resolve according to appropriate hit chart.
# Also, check and apply a penalty as necessary for the 'pilot_training' status.


# Massive Deployment function:  input 'status' to 'active' or 'inactive'
# if 'active', +1 ship to basestar launch actions
# resets on fleet 'jump'.

#turn actions
#Lets player choose actions to preform on turn

# move function:  move input player (or players at location) to input location
# also, "current_choice" allows current player to move a player of choice to input location
def move(current_player,location,players):
    if player=='current':
        print "something"
        

def turn_actions(players,skills,characters,phase):
    choice = raw_input('\nPress Letter to confirm choice, or (V) to view character, or (Y) to view loyalty: ')
    if choice=='M':
        print "move function"
    elif choice=='A':
        print "action function"
    elif choice=='L':
        print "location function"
    elif choice=='C':
        print "character view function"
    elif choice=='B':
        print "view board"
    elif choice=='Y':
        print i['loyalty']
                       

    return players
